package callbacks;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;

import javax.mail.Address;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.Message.RecipientType;
import javax.mail.Multipart;

import models.GmailEmail;

import com.sun.mail.gimap.GmailFolder;
import com.sun.mail.gimap.GmailMessage;
import com.sun.mail.gimap.GmailSSLStore;

import play.libs.Akka;
import play.libs.F;
import play.libs.F.Function;
import play.libs.F.Option;
import play.libs.F.Promise;
import play.libs.F.Tuple;
import play.libs.Json;
import play.mvc.Controller;
import play.mvc.Result;
import services.GoogleService;

public class GMailCallbacks extends Controller {

	public static class FolderSlot {
			Option<GmailFolder> folder = F.None();
		}

	public static class ConnectToStore implements
				Function<GmailSSLStore, Promise<GmailSSLStore>> {
	
			private String email;
	
			public ConnectToStore(String email) {
				this.email = email;
			}
	
			@Override
			public Promise<GmailSSLStore> apply(GmailSSLStore store)
					throws Throwable {
				return GoogleService.connectStore(store, email);
			}
	
		}

	public static class StoreToFolder implements
				Function<GmailSSLStore, Promise<GmailFolder>> {
	
			private String folderName;
	
			public StoreToFolder(String folderName) {
				this.folderName = folderName;
			}
	
			@Override
			public Promise<GmailFolder> apply(GmailSSLStore store) throws Throwable {
				return GoogleService.getFolder(store, folderName);
			}
		}

	public static class FolderToSearch implements
				Function<GmailFolder, Promise<Tuple<Message[],GmailFolder>>> {
	
			private String query;
	
			public FolderToSearch(String query) {
				this.query = query;
			}
	
			@Override
			public Promise<Tuple<Message[],GmailFolder>> apply(GmailFolder folder) throws Throwable {
				return GoogleService.search(folder, query);
			}
		}

	public static class MessagesToFetch implements
				Function<Tuple<Message[],GmailFolder>, Promise<Tuple<Message[],GmailFolder>>> {
	
			@Override
			public Promise<Tuple<Message[],GmailFolder>> apply(Tuple<Message[],GmailFolder> t) throws Throwable {
				return GoogleService.fetch(t._2, t._1);
			}
		}

	public static class MessagesToRequest implements
				Function<Tuple<Message[],GmailFolder>, Promise<Result>> {
	
			private GmailFolder folder;
			
			private int max;
			
			public MessagesToRequest(int max) {
				this.max = max;
			}
	
			@Override
			public Promise<Result> apply(final Tuple<Message[],GmailFolder> t) throws Throwable {
	
				return Akka.future(new Callable<Result>() {
					@Override
					public Result call() throws Exception {
						try {
							folder = t._2;
							List<GmailEmail> emails = new ArrayList<GmailEmail>();
							Message[] messageArr = t._1; 
							int maxRequests = max;
							for (int i = messageArr.length - 1; i >= 0 && maxRequests > 0; i--) {
								maxRequests--;
								Message m = messageArr[i];
								GmailMessage message = (GmailMessage) m;
								// gmail special ids
								// https://developers.google.com/google-apps/gmail/imap_extensions#access_to_the_gmail_unique_message_id_x-gm-msgid
								long msgId = message.getMsgId();
								long thrId = message.getThrId();
								String subject = message.getSubject();
								Address[] fromArray = message.getFrom();
								Address[] ccArray = message
										.getRecipients(RecipientType.CC);
								Address[] toArray = message
										.getRecipients(RecipientType.TO);
								Date received = message.getReceivedDate();
								Date sent = message.getSentDate();
								
								String content = "";
								if (message.getContent() instanceof Multipart) {
									Multipart multipart = (Multipart) message.getContent();
									for (int j = 0; j < multipart.getCount(); j++) {
										//TODO how to skip repeated parts from a message?
										BodyPart bodypart = multipart.getBodyPart(j);
										String disposition = bodypart.getDisposition();
										if (disposition != null && disposition.equals(BodyPart.ATTACHMENT)) {
											//skip for now
	//									DataHandler handler = bodyPart.getDataHandler();
	//									System.out.println("file name : " + handler.getName());
										} else {
											content += bodypart.getContent().toString();
										}
									}
								} else {
									content += message.getContent().toString();
								}
	
								String from = fromArray[0].toString();
								List<String> cc = new ArrayList<String>();
								if (ccArray != null) {
									for (Address address : ccArray) {
										cc.add(address.toString());
									}
								}
								
								List<String> to = new ArrayList<String>();
								if (toArray != null) {
									for (Address address : toArray) {
										to.add(address.toString());
									}
								}
	
								GmailEmail email = new GmailEmail();
								email.cc = cc;
								email.to = to;
								email.content = content;
								email.from = from;
								email.msgId = msgId;
								email.received = received.getTime();
								email.sent = sent.getTime();
								email.subject = subject;
	
								emails.add(email);
							}
	
							return ok(Json.toJson(emails));
						} finally {
							if (folder.isOpen()) {
								folder.close(true);
							}
						}
	
					}
				});
			}
		}

	public GMailCallbacks() {
		super();
	}

}